package genetic.selection;

import genetic.interfaces.Individual;
import genetic.interfaces.Population;
import genetic.interfaces.Selection;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Random;

public class MarioSelection<Fitness extends Number & Comparable<Fitness>, I extends Individual<?, Fitness>> implements Selection<I> {

	private Population<I> pop;
	private Random random;
	
	public MarioSelection(Population<I> pop) {
		this.pop = pop;
		random = new Random();
	}
	
	/*
	 * Seleção por roleta
	 */
	@Override
	@SuppressWarnings("unchecked")
	public I[] select() {
		double lowestFitness, greatestFitness;
        double total = 0.0;
        double sum = 0.0;
        ArrayList<I> parents = new ArrayList<I>();
        
        double w[] = new double[pop.getNumberOfIndividuals()];
        I individuals[] = pop.getIndividuals();
        
        
        //Cálculo dos pesos:
        lowestFitness   = pop.getWorst().eval().doubleValue();
        greatestFitness = pop.getBest().eval().doubleValue();
        
        if(lowestFitness == greatestFitness){
        	 parents.add(individuals[0]);
             parents.add(individuals[1]);
             return (I[]) parents.toArray( (I[]) Array.newInstance(parents.get(0).getClass(), parents.size()));
        }
        
        for ( int i = 0; i < w.length; i++){
        	w[i] = individuals[i].eval().doubleValue() - lowestFitness;
        	total += w[i];
        }
        
        
        for (int i = 0; i < w.length; i++) {
            w[i] = sum + w[i]/total;
            sum = w[i];
        }
        
        //Escolha dos pais:
        double x;
        int p1, p2; 
        
        x = random.nextDouble();
        p1 = 0;
        while( p1 < w.length - 1 && x > w[p1] )
            p1++;
       
        if(sum - w[p1] == 0){
        	p2 = 0;
        }else{
        	p2 = p1;
        }
        
        while (p1 == p2) {         
            x = random.nextDouble();
            p2 = 0;
            while( p2 < w.length - 1 && x > w[p2] )
                p2++;     
        };
        
        parents.add(individuals[p1]);
        parents.add(individuals[p2]);
        
        return (I[]) parents.toArray( (I[]) Array.newInstance(parents.get(0).getClass(), parents.size()));
	}
	
}
